﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;
using System.IO;

namespace 根据等高线绘制剖面图
{
    public partial class Form1 : Form
    {
        AcadApplication AcadApp;
        AcadDocument AcadDoc;

        public Form1()
        {
            InitializeComponent();
        }

        private void 启动CAD()
        {
            try
            {
                AcadApp =
               (AcadApplication)System.Runtime.InteropServices.Marshal.GetActiveObject("AutoCAD.Application");
                AcadDoc = AcadApp.ActiveDocument;
            }
            catch
            {
                OpenFileDialog pOpenDG = new OpenFileDialog();
                pOpenDG.Filter = "CAD文件(*.dwg)|*.dwg|CAD图形文件(*.dxf)|*.dxf";
                pOpenDG.Title = "打开CAD文件";
                pOpenDG.ShowDialog();
                string filePath = pOpenDG.FileName;
                if (filePath == "")
                {
                    MessageBox.Show("选择CAD文件无效！", "文件无效！");
                    Application.Exit();
                }
                AcadApp = new AcadApplication();
                AcadDoc = AcadApp.Documents.Open(filePath, null, null);
            }
            AcadApp.Application.Visible = true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            启动CAD();
            刷新图层显示();
        }

        private void 获取两条多段线的交点_Click(object sender, EventArgs e)
        {
            handle01:
            Microsoft.VisualBasic.Interaction.AppActivate(AcadApp.Caption);
            object returnObj1, returnObj2, pickPoint;
            string pickPrompt = "选取多段线!";
            AcadDoc.Utility.GetEntity(out returnObj1, out pickPoint, pickPrompt);
            AcadObject returnCADObj1 = (AcadObject)returnObj1;
            if (returnCADObj1.ObjectName != "AcDbPolyline")
            {
                MessageBox.Show("选择的不是多段线，请重新选择！");
                goto handle01;
            }
            handle02:
            AcadDoc.Utility.GetEntity(out returnObj2, out pickPoint, pickPrompt);
            AcadObject returnCADObj2 = (AcadObject)returnObj2;
            if (returnCADObj2.ObjectName != "AcDbPolyline")
            {
                MessageBox.Show("选择的不是多段线，请重新选择！");
                goto handle02;
            }
            AcadLWPolyline returnLine = (AcadLWPolyline)returnCADObj2;
            Double[] result;
            result = (Double[])returnLine.IntersectWith(returnCADObj1,
           AcExtendOption.acExtendBoth);
            if (result.Length > 0)
            {
                string showInfo = "交点坐标为：";
                int i;
                for (i = 0; i < result.Length - 1; i++)
                {
                    showInfo += result[i].ToString() + ",";
                }
                showInfo += result[i].ToString();
                MessageBox.Show(showInfo);
            }
            else
            {
                MessageBox.Show("选择两条多段线没有交点！");
            }
        }

        private void 根据等高线绘制剖面图_Click(object sender, EventArgs e)
        {
            handle01:
            Microsoft.VisualBasic.Interaction.AppActivate(AcadApp.Caption);
            object returnObj, pickPoint;
            string pickPrompt = "选取多段线!";
            AcadDoc.Utility.GetEntity(out returnObj, out pickPoint, pickPrompt);
            AcadObject returnCADObj = (AcadObject)returnObj;
            if (returnCADObj.ObjectName == "AcDbPolyline")
            {
                AcadLWPolyline polyline = (AcadLWPolyline)returnCADObj;
                object minPoint, maxPoint;
                double[] minPointCoord = new double[3], maxPointCoord = new double[3];
                polyline.GetBoundingBox(out minPoint, out maxPoint);
                minPointCoord = (double[])minPoint;
                maxPointCoord = (double[])maxPoint;

                AcadSelectionSet mySelectionSet;
                mySelectionSet = AcadDoc.SelectionSets.Add("NewSelectionSet01");
                Int16[] FilterType = new Int16[1];
                object[] FilterData = new object[1];
                FilterType[0] = 8;
                FilterData[0] = LayerComboBox.Text;
                double[] selEdgePoints = new double[12];
                selEdgePoints[0] = minPointCoord[0]; selEdgePoints[1] = minPointCoord[1];
                selEdgePoints[2] = minPointCoord[2];
                selEdgePoints[3] = maxPointCoord[0]; selEdgePoints[4] = minPointCoord[1];
                selEdgePoints[5] = minPointCoord[2];
                selEdgePoints[6] = maxPointCoord[0]; selEdgePoints[7] = maxPointCoord[1];
                selEdgePoints[8] = maxPointCoord[2];
                selEdgePoints[9] = minPointCoord[0]; selEdgePoints[10] = maxPointCoord[1];
                selEdgePoints[11] = maxPointCoord[2];
                mySelectionSet.SelectByPolygon(AcSelect.acSelectionSetCrossingPolygon,
                    selEdgePoints, FilterType, FilterData);
                double[] CoordValue = new double[mySelectionSet.Count * 3 + 3];
                int coordCount = 0;
                foreach (AcadObject selectCADObj in mySelectionSet)
                {
                    if (returnCADObj.ObjectName == "AcDbPolyline")
                    {
                        AcadLWPolyline contourObj = (AcadLWPolyline)selectCADObj;
                        polyline.Elevation = contourObj.Elevation;
                        double[] result;
                        result = (double[])polyline.IntersectWith(contourObj,
                       AcExtendOption.acExtendNone);
                        if (result.Length > 0)
                        {
                            CoordValue[3 * coordCount] = result[0];
                            CoordValue[3 * coordCount + 1] = result[1];
                            CoordValue[3 * coordCount + 2] = result[2];
                            CoordValueTextBox.Text += result[0].ToString() + "," +
                           result[1].ToString() + "," + result[2].ToString() + "\n";
                            coordCount++;
                        }
                    }
                }
                MessageBox.Show("在平面线范围内有" + mySelectionSet.Count.ToString() + "条等高线！");
                AcadDoc.SelectionSets.Item("NewSelectionSet01").Delete();
                DoArrayList(CoordValue, coordCount, out CoordValue, 1);
                DrawProfile(CoordValue, coordCount, Double.Parse(textBox1.Text),  Double.Parse(textBox2.Text));
            }
            else
            {
                MessageBox.Show("选择的不是多段线，请重新选择！");
                goto handle01;
            }
        }

        private void 刷新图层显示()
        {
            LayerComboBox.Items.Clear();
            int i;
            for (i = 0; i < AcadDoc.Layers.Count; i++)
            {
                LayerComboBox.Items.Add(AcadDoc.Layers.Item(i).Name.ToString());
            }
            LayerComboBox.Text = AcadDoc.ActiveLayer.Name.ToString();
        }

        private double GetDistance(double[] point01, double[] point02)
        {
            double distance;
            distance = Math.Sqrt(Math.Pow((point01[0] - point02[0]), 2) + Math.Pow((point01[1] -
           point02[1]), 2));
            return distance;
        }

        private double GetDistance(double point01X, double point01Y, double point02X, double point02Y)
        {
            double distance;
            distance = Math.Sqrt(Math.Pow((point01X - point02X), 2) + Math.Pow((point01Y - point02Y),
           2));
            return distance;
        }

        private void DrawProfile(double[] vertexCoords, int coordCount, double oX, double oY)//绘制剖面图
        { 
            double minZ, maxZ;
            int maxZIndex = 0;
            maxZ = minZ = vertexCoords[2]; 
            for (int i = 1; i<coordCount; i++) 
            { 
                if (maxZ<vertexCoords[3 * i + 2]) 
                { 
                    maxZ = vertexCoords[3 * i + 2]; 
                    maxZIndex = i; 
                } 
                if (minZ > vertexCoords[3 * i + 2]) 
                { 
                    minZ = vertexCoords[3 * i + 2]; 
                } 
            }

            double[] newCoords = new double[coordCount * 2];
            newCoords[0] = oX;
            newCoords[1] = oY + vertexCoords[2] - minZ;
            for (int i = 1; i < coordCount; i++)
            {
                newCoords[2 * i] = newCoords[2 * i - 2] + GetDistance(vertexCoords[3 * i - 3],
               vertexCoords[3 * i - 2], vertexCoords[3 * i], vertexCoords[3 * i + 1]);
                newCoords[2 * i + 1] = oY + vertexCoords[3 * i + 2] - minZ;
            }

            double[] point0 = new double[3], point1 = new double[3], point2 = new double[3], point3 =
new double[3],
 point4 = new double[3], point5 = new double[3], point6 = new double[3], point7 = new
double[3], point8 = new double[3];

            point0[0] = oX; point0[1] = oY;
            point1[0] = newCoords[2 * coordCount - 2] + 20; point1[1] = oY;
            point2[0] = oX; point2[1] = oY + maxZ - minZ + 20;
            point3[0] = point1[0] + 10; point3[1] = oY;
            point4[0] = oX; point4[1] = point2[1] + 10;
            point5[0] = newCoords[2 * maxZIndex]; point5[1] = newCoords[2 * maxZIndex + 1];
            point6[0] = oX; point6[1] = oY + maxZ - minZ;
            point7[0] = newCoords[2 * coordCount - 2]; point7[1] = newCoords[2 * coordCount - 1];
            point8[0] = point7[0]; point8[1] = oY;
            AcadDoc.ModelSpace.AddLine(point0, point1);//绘制横轴

            AcadDoc.ModelSpace.AddLine(point0, point2);//绘制纵轴
                                                       //横轴方向箭头
            AcadLWPolyline arrow1;
            double[] arrowCoord1 = new double[4];
            arrowCoord1[0] = point1[0]; arrowCoord1[1] = point1[1];
            arrowCoord1[2] = point3[0]; arrowCoord1[3] = point3[1];
            arrow1 = (AcadLWPolyline)AcadDoc.ModelSpace.AddLightWeightPolyline(arrowCoord1);
            arrow1.SetWidth(0, 3, 0);
            //纵轴方向箭头
            AcadLWPolyline arrow2;
            double[] arrowCoord2 = new double[4];
            arrowCoord2[0] = point2[0]; arrowCoord2[1] = point2[1];
            arrowCoord2[2] = point4[0]; arrowCoord2[3] = point4[1];
            arrow2 = (AcadLWPolyline)AcadDoc.ModelSpace.AddLightWeightPolyline(arrowCoord2);
            arrow2.SetWidth(0, 3, 0);
            AcadDoc.ModelSpace.AddLine(point5, point6);//绘制最高线
            AcadDoc.ModelSpace.AddLine(point7, point8);//绘制最远线除了绘制基本框架线条外，还有文字部分，包括“里程”、“高程”、“O”等等，如下图所示

            double[] point9 = new double[3], point10 = new double[3], point11 = new double[3], point12
= new double[3], point13 = new double[3];
            point9[0] = point0[0]; point9[1] = point0[1] - 12;//假定文字距离原点为20 
            point10[0] = point8[0]; point10[1] = point8[1] - 12;
            point11[0] = point6[0] - 30; point11[1] = point6[1];
            point12[0] = point0[0] - 30; point12[1] = point0[1];
            point13[0] = (point0[0] + point8[0]) / 2 - 20; point13[1] = point4[1];
            AcadDoc.ModelSpace.AddText("里程", point3, 10);//假定文字高度为10 
            AcadDoc.ModelSpace.AddText("高程", point4, 10);
            AcadDoc.ModelSpace.AddText("o", point9, 10);
            AcadDoc.ModelSpace.AddText((newCoords[2 * coordCount - 2] - oX).ToString("##.##"), point10, 10);
            AcadDoc.ModelSpace.AddText(maxZ.ToString("##.##"), point11, 10);
            AcadDoc.ModelSpace.AddText(minZ.ToString("##.##"), point12, 10);
            AcadDoc.ModelSpace.AddText("剖面图", point13, 15);
            AcadDoc.ModelSpace.AddLightWeightPolyline(vertexCoords);
        }

        private void DoArrayList(double[] arrayIn, int arrayLength, out double[] arrayOut, int mode)
        {
            arrayOut = new double[3 * arrayLength];
            if (mode == 1)
            {
                for (int i = 0; i < arrayLength - 1; i++)
                {
                    for (int j = i + 1; j < arrayLength; j++)
                    {
                        if (arrayIn[3 * i] > arrayIn[3 * j])
                        {
                            double[] temp = new double[3];
                            temp[0] = arrayIn[3 * j]; temp[1] = arrayIn[3 * j + 1]; temp[2] = arrayIn[3
                           * j + 2];
                            arrayIn[3 * j] = arrayIn[3 * i]; arrayIn[3 * j + 1] = arrayIn[3 * i + 1];
                            arrayIn[3 * j + 2] = arrayIn[3 * i + 2];
                            arrayIn[3 * i] = temp[0]; arrayIn[3 * i + 1] = temp[1]; arrayIn[3 * i + 2]
                           = temp[2];
                        }
                    }
                }
            }
            else if (mode == 2)
            {
                for (int i = 0; i < arrayLength - 1; i++)
                {
                    for (int j = i + 1; j < arrayLength; j++)
                    {
                        if (arrayIn[3 * i] < arrayIn[3 * j])
                        {
                            double[] temp = new double[3];
                            temp[0] = arrayIn[3 * j]; temp[1] = arrayIn[3 * j + 1]; temp[2] = arrayIn[3
                           * j + 2];
                            arrayIn[3 * j] = arrayIn[3 * i]; arrayIn[3 * j + 1] = arrayIn[3 * i + 1];
                            arrayIn[3 * j + 2] = arrayIn[3 * i + 2];
                            arrayIn[3 * i] = temp[0]; arrayIn[3 * i + 1] = temp[1]; arrayIn[3 * i +
                           2] = temp[2];
                        }
                    }
                }
            }
            arrayOut = arrayIn;
        }
    }
}
